/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package lexico;

import java.util.ArrayList;
import java.util.List;
import java.util.ResourceBundle;
import java.util.regex.Pattern;
import util.PalavrasReservadas;

/**
 *
 * @author Administrador
 */
public class AnalisadorLexico {
    
   private ResourceBundle regexEstadosAnalisadorLexico;
     
   

    private String codigoFonte;
    private List<Erro> erros;
    private List<Token> tokens;
    private int numeroDaLinha;
    private int numeroDaColuna;

    
    private int linhaDoUltimoComentarioAberto;
    private boolean comentarioAberto;
    private String token = "";
    private Integer index = 0;
    private String atual;
    String teste;
    public AnalisadorLexico() {
        super(); 
        regexEstadosAnalisadorLexico = ResourceBundle.getBundle("util.RegexAutomato");
        erros = new ArrayList<Erro>();
        tokens = new ArrayList<Token>();
    }
    

    public String getCodigoFonte() {
        return codigoFonte;
    }

    public void setCodigoFonte(String codigoFonte) {
        this.codigoFonte = codigoFonte;
    }

    public List<Erro> getErros() {
        return erros;
    }

    public void setErros(List<Erro> erros) {
        this.erros = erros;
    }

    public List<Token> getTokens() {
        return tokens;
    }

    public void setTokens(List<Token> tokens) {
        this.tokens = tokens;
    }

    public int getNumeroDaLinha() {
        return numeroDaLinha;
    }

    public void setNumeroDaLinha(int numeroDaLinha) {
        this.numeroDaLinha = numeroDaLinha;
    }
    
    public int getNumeroDaColuna() {
        return numeroDaColuna;
    }

    public void setNumeroDaColuna(int numeroDaColuna) {
        this.numeroDaColuna = numeroDaColuna;
    }

    public int getLinhaDoUltimoComentarioAberto() {
        return linhaDoUltimoComentarioAberto;
    }

    public void setLinhaDoUltimoComentarioAberto(int linhaDoUltimoComentarioAberto) {
        this.linhaDoUltimoComentarioAberto = linhaDoUltimoComentarioAberto;
    }

    public boolean isComentarioAberto() {
        return comentarioAberto;
    }

    public void setComentarioAberto(boolean comentarioAberto) {
        this.comentarioAberto = comentarioAberto;
    }

    public String getToken() {
        return token;
    }

    public void setToken(String token) {
        this.token = token;
    }

    public Integer getIndex() {
        return index;
    }

    public void setIndex(Integer index) {
        this.index = index;
    }

    public String getAtual() {
        return atual;
    }

    public void setAtual(String atual) {
        this.atual = atual;
    }
    
    
    
     public void analisar() {
        erros = new ArrayList<Erro>();// cria uma lista para armazenar os erros
        tokens = new ArrayList<Token>();// lista de tokens        
        index = 0;
        numeroDaLinha = 1;
        numeroDaColuna = 0;

        if (!codigoFonte.isEmpty()){ //caso a variavel cod.fonte tiver vazia pega o primeiro caracter
            firstChar();
        }
        
        while(index < codigoFonte.length()) { 
             if (currentChar().equals(" ") || currentChar().equals("\f") || currentChar().equals("\t")) {
                token = "";
                nextChar();
                numeroDaColuna = numeroDaColuna -1;//nao conta a coluna
                continue;
            } else if (currentChar().equals("\n")) {
                numeroDaLinha++;
                numeroDaColuna = 0;//zera a coluna
                token = "";
                nextChar();
                continue;
            }else if (Pattern.matches(regexEstadosAnalisadorLexico.getString("i0A"), currentChar().toString())) {                                                                                                                
                token += currentChar();
                estadoA();
            } else if (Pattern.matches(regexEstadosAnalisadorLexico.getString("i0B"), currentChar().toString())) {
                token += currentChar();
                estadoB();
            } else if (Pattern.matches(regexEstadosAnalisadorLexico.getString("i0D"), currentChar().toString())) {
                token += currentChar();
                estadoD();
            } else if (Pattern.matches(regexEstadosAnalisadorLexico.getString("i0i1"), currentChar().toString())) {
                token += currentChar();
                estadoi1();
            } else if (Pattern.matches(regexEstadosAnalisadorLexico.getString("i0L"), currentChar().toString()) ||
                       Pattern.matches(",", currentChar().toString())) {
                token += currentChar();
                estadoi1();
            }else if (Pattern.matches(regexEstadosAnalisadorLexico.getString("i1M"), currentChar())) {
                token += currentChar();
                estadoi1();
            
            }else if (Pattern.matches(regexEstadosAnalisadorLexico.getString("EF"), currentChar().toString())) {
                token += currentChar();
                estadoF();
            }else if (Pattern.matches(regexEstadosAnalisadorLexico.getString("i1i1"), currentChar().toString())) {
                token += currentChar();
                estadoE();
            }
            else {
                token += currentChar();
                tokens.add(new Token(token, TipoToken.INVALIDO, numeroDaLinha,numeroDaColuna));
                nextChar();
            }
              
            //nextChar();// pega o proximo caracter para continuar a analise.
                
            
            
        }
     }
        
        
    
     
     
      public String currentChar(){
        return atual;
    }

    public void nextChar(){
        try{
            atual = ((Character) codigoFonte.charAt(++index)).toString();
            numeroDaColuna ++;
        } catch (StringIndexOutOfBoundsException e) {
            atual = "FIM DO FONTE"; // Esse try-catch block é uma gambiarra de fim da string :), reverrrr....
            return;
        }
    }

    public void firstChar(){
        atual = ((Character) codigoFonte.charAt(0)).toString();//pega o primeiro caracter do fonte.
    }
    
    private void estadoA(){
        nextChar();//o caracter anterior ja foi analisado, entao pega o proximo
        if (Pattern.matches(regexEstadosAnalisadorLexico.getString("AA"), currentChar())) {//verifica o padrão do caracter...
            token += currentChar();// caso tenha o padrão entao adiciona no token.
            estadoA();//recursão, para verificar o token inteiro
        } else if(Pattern.matches(regexEstadosAnalisadorLexico.getString("BC"), currentChar().toString()) && (!token.equalsIgnoreCase("this"))  ){ //this é palavra reservada
            token += currentChar();// caso tenha o padrão entao adiciona no token.
            estadoA();//recursão, para verificar o token inteiro
        }//verificação do SYSTEM.OUT.PRINTLN       
        else {
            definetoken(token, numeroDaLinha);//indica que terminou o token entao define o mesmo
        }
    }
    
    private void estadoi1(){
        nextChar();
        construirDelimitador(token, numeroDaLinha);
        
        
    }
    
    private void estadoM(){
        nextChar();
        comentarioAberto = false;
    }
    
    private void estadoE(){
        nextChar();         
        construirDelimitador(token, numeroDaLinha);
        
    }
       private void estadoF(){
        nextChar();
        if (Pattern.matches(regexEstadosAnalisadorLexico.getString("EF"), currentChar().toString())) {
                token += currentChar();
                if (Pattern.matches(regexEstadosAnalisadorLexico.getString("EI"), token)) {
                    nextChar();
                    construirDelimitador(token, numeroDaLinha);
                }else{
                    estadoE();
                }
        }else{
            estadoE();
        }
        
        
    }
    
    private void estadoD(){
        nextChar();        
        construirDelimitador(token, numeroDaLinha);
        
    }
    private void estadoB(){
        nextChar();
        if (Pattern.matches(regexEstadosAnalisadorLexico.getString("BB"), currentChar())) {
            token += currentChar();
            estadoB();        
        } else {
            construirNumeroInteiro(token, numeroDaLinha);
        }
    }
    
    
    private void definetoken(String token, int numeroDaLinha) {
        PalavrasReservadas reservadas = PalavrasReservadas.getInstance();
        if (reservadas.isPalavraReservada(token)){//verifica se é uma palavra reservada
            tokens.add(new Token(token, TipoToken.PALAVRA_RESERVADA, numeroDaLinha,numeroDaColuna));// se for palavra reservada então o token é definido como tal.
            this.token = ""; // "zera" o token
        } else {//se nao for reservada cria um identificar....
            tokens.add(new Token(token, TipoToken.IDENTIFICADOR, numeroDaLinha,numeroDaColuna));//adiona o token como sendo uma variavel difinida pelo user.
            this.token = "";//"zera" o token.
        }
    }
    
    private void construirDelimitador(String token, int numeroDaLinha) {
        tokens.add(new Token(token, Define_tipo_token(token), numeroDaLinha,numeroDaColuna));
        this.token = "";
    }
    
    private void construirNumeroInteiro(String token, int numeroDaLinha) {
        tokens.add(new Token(token, TipoToken.NUMERO_INTEIRO, numeroDaLinha,numeroDaColuna));
        this.token = "";
    }
    
    private TipoToken Define_tipo_token(String token){
        TipoToken result = null ;
        if(token.equals("(")){
            result = TipoToken.DELIMITADOR_PARENTESE_ESQUERDO;
        }else if (token.equals(")")){
            result = TipoToken.DELIMITADOR_PARENTESE_DIREITO;            
        }else if (token.equals("{")){
            result = TipoToken.DELIMITADOR_CHAVE_ESQUERDA;            
        }else if (token.equals("}")){
            result = TipoToken.DELIMITADOR_CHAVE_DIREITA;            
        }else if (token.equals("[")){
            result = TipoToken.DELIMITADOR_COLCHETE_ESQUERDO;            
        }else if (token.equals("]")){
            result = TipoToken.DELIMITADOR_COLCHETE_DIREITO;            
        }else if (token.equals(".")){
            result = TipoToken.PONTUACAO_PONTO;            
        }else if (token.equals(";")){
            result = TipoToken.PONTUACAO_PONTO_E_VIRGULA;            
        }else if (token.equals(",")){
            result = TipoToken.PONTUACAO_VIRGULA;            
        }else if (token.equals("=")){
            result = TipoToken.OPERADOR_ATRIBUICAO;
        }else if (token.equals("+")){
            result = TipoToken.OPERADOR_ADITIVO;
        }else if (token.equals("-")){
            result = TipoToken.OPERADOR_ADITIVO;
        }else if (token.equals("*")){
            result = TipoToken.OPERADOR_MULTIPLICATIVO;
        }else if (token.equals("/")){
            result = TipoToken.OPERADOR_MULTIPLICATIVO;
        }else if (token.equals("==")){
            result = TipoToken.OPERADOR_RELACIONAL_IGUAL;
        }else if (token.equals("<")){
            result = TipoToken.OPERADOR_RELACIONAL_MENOR_QUE;
        }else if (token.equals(">")){
            result = TipoToken.OPERADOR_RELACIONAL_MAIOR_QUE;
        }else if (token.equals("!=")){
            result = TipoToken.OPERADOR_RELACIONAL_DIFERENTE;
        }else if (token.equals("'")){
            result = TipoToken.ASPAS_SIMPLES;
        }else if (token.equals('"')){
            result = TipoToken.ASPAS_DUPLAS;
        }
        
       return result;
        
        
    }
    
}



